/**
 * 
 */
package gopi.labs.utils;

import gopi.labs.Connector.NameValue;
import gopi.labs.database.DataStreamMapping;
import gopi.labs.exceptions.InValidIdentifier;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.sun.net.httpserver.HttpServer;

/**
 * @author Gopinath
 * 
 */
public class DataLoader implements Runnable {

	/**
	 * @param args
	 */
	private String cloudSpace;
	private String dataModel;
	private String dataStream;
	private Connection connection;
	private Properties properties;
	private int port;
	
	

	private List<DataStreamMapping> dataStreamMapping;

	public DataLoader(String cloudSpace, String dataModel, String dataStream , int port)
			throws IOException, ClassNotFoundException, SQLException {
		this.setCloudSpace(cloudSpace);
		this.setDataModel(dataModel);
		this.setDataStream(dataStream);
		this.setPort(port);
		this.dataStreamMapping = new ArrayList<DataStreamMapping>();
		readParams();
		connect();
		readDataStream();
		this.disconnect();
	}

	public void connect() throws SQLException, ClassNotFoundException {

		Class.forName(this.properties.getProperty("HSQLDB_CLASS"));

		this.connection = DriverManager.getConnection(
				this.properties.getProperty("HSQLDB_URL"),
				this.properties.getProperty("HSQLDB_USER"),
				this.properties.getProperty("HSQLDB_PASSWORD"));

		this.connection.setAutoCommit(false);
	}

	public void process(List<NameValue> data) throws SQLException,
			InValidIdentifier {
		Statement stmt = this.connection.createStatement();
		StringBuffer columns = new StringBuffer();
		StringBuffer values = new StringBuffer();

		for (int i = 0; i < data.size(); i++) {

			if (i == 0) {
				columns.append(getDataModelColumnName(data.get(i).getName()
						.toString()));
				values.append("'" + data.get(i).getValue() + "'");
			} else {
				columns.append(","
						+ getDataModelColumnName(data.get(i).getName()
								.toString()));
				values.append(",'" + data.get(i).getValue() + "'");
			}
		}
		System.out.println("INSERT INTO " + this.getCloudSpace() + "."
				+ this.getDataModel() + "(" + columns.toString() + ")"
				+ "VALUES (" + values.toString() + ")");
		stmt.execute("INSERT INTO " + this.getCloudSpace() + "."
				+ this.getDataModel() + "(" + columns.toString() + ")"
				+ "VALUES (" + values.toString() + ")");
		this.connection.commit();
	}

	private String getDataModelColumnName(String srcColumnName)
			throws InValidIdentifier {

		if (srcColumnName != null && srcColumnName.equalsIgnoreCase("DATETIME")) return srcColumnName;
		
		for (int i = 0; i < this.getdataStreamMapping().size(); i++) {
			if (srcColumnName != null
					&& srcColumnName.equalsIgnoreCase(this
							.getdataStreamMapping().get(i).getSrcColumnName()))
				return srcColumnName;
		}
		throw new InValidIdentifier(
				"Destination Column not present for srcCOlumn " + srcColumnName);
	}

	private void readDataStream() throws SQLException {
		Statement stmt = this.connection.createStatement();
		System.out.println("select src_column_name, dst_column_name, position from metadata.data_stream_mapping "
				+ " where cloud_name = '"
				+ this.getCloudSpace()
				+ "' and data_model_name = '"
				+ this.getDataModel()
				+ "' and name ='"
				+ this.getDataStream()
				+ "' order by position");
		ResultSet rs = stmt
				.executeQuery("select src_column_name, dst_column_name, position from metadata.data_stream_mapping "
						+ " where cloud_name = '"
						+ this.getCloudSpace()
						+ "' and data_model_name = '"
						+ this.getDataModel()
						+ "' and name ='"
						+ this.getDataStream()
						+ "' order by position");

		while (rs.next()) {
			this.dataStreamMapping.add(new DataStreamMapping(rs.getString(1),
					rs.getString(2), rs.getInt(3)));
		}
	}

	private void disconnect() throws SQLException {
		this.connection.close();
	}

	public void readParams() throws IOException {
		this.properties = new Properties();
		InputStream is = new FileInputStream("config.properties");
		properties.load(is);

	}

	/**
	 * @return the cloudSpace
	 */
	public String getCloudSpace() {
		return cloudSpace;
	}

	/**
	 * @param cloudSpace
	 *            the cloudSpace to set
	 */
	public void setCloudSpace(String cloudSpace) {
		this.cloudSpace = cloudSpace.toUpperCase();
	}

	/**
	 * @return the dataModel
	 */
	public String getDataModel() {
		return dataModel;
	}

	/**
	 * @param dataModel
	 *            the dataModel to set
	 */
	public void setDataModel(String dataModel) {
		this.dataModel = dataModel.toUpperCase();
	}

	/**
	 * @return the dataStream
	 */
	public String getDataStream() {
		return dataStream;
	}

	/**
	 * @param dataStream
	 *            the dataStream to set
	 */
	public void setDataStream(String dataStream) {
		this.dataStream = dataStream.toUpperCase();
	}

	public List<DataStreamMapping> getdataStreamMapping() {
		return dataStreamMapping;
	}

	public void setdataStreamMapping(List<DataStreamMapping> dataStreamMapping) {
		this.dataStreamMapping = dataStreamMapping;
	}
	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}
	@Override
	public void run() {
		HttpServer server;
		try {
			server = HttpServer.create(new InetSocketAddress(this.getPort()), 0);
			System.out.println(this.getDataStream());
			server.createContext("/" + this.getDataStream(), new DataHandler(
					this));
			server.setExecutor(null); // creates a default executor
			server.start();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}


}